/*
 * @Author       : Bing Chen chenbing@iocharger.com
 * @Date         : 2024-05-20 22:30:35
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 12:58:07
 * @FilePath     : \openchaoji-corelib\shared\include\OpenChaoJi_debug.h
 * @Description  : 通用调试打印接口
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */

#ifndef __OPEN_CHAOJI_DEBUG_H__
#define __OPEN_CHAOJI_DEBUG_H__

#include "OpenChaoJi_config.h"
#include "OpenChaoJi_type.h"

/**
 * 系统级: 设置LOG等级
 *  @level: LOG等级
 * 表示期望设置的日志等级，不同的等级对应不同的日志输出详细程度，
 * 例如，较低等级可能仅输出严重错误信息，而较高等级会输出包括调试信息在内的更详细内容，方便开发人员在不同阶段（如开发调试阶段、正式运行阶段等）根据需求灵活控制日志输出量
*/
#define OPENCHAOJI_SET_LOGLEVEL(level)       OpenChaoJi_debug_set_log_level(level)



// LOG_LEVEL 定义
#define DBGL_EMERG      (1 << 0)    // 紧急消息,系统崩溃之前提示,表示系统已不可用
#define DBGL_ALERT      (1 << 1)    // 报告消息,表示必须立即采取措施
#define DBGL_CRIT       (1 << 2)    // 临界消息,通常涉及严重的硬件或软件操作失败
#define DBGL_ERR        (1 << 3)    // 错误消息,由于严重的问题,某些功能已经不能正常使用
#define DBGL_WARNING    (1 << 4)    // 警告消息,对可能出现问题的情况进行警告
#define DBGL_NOTICE     (1 << 5)    // 通知消息,正常但又重要的消息,用于提醒,常用于与安全相关的消息,一般是程序设定的默认级别
#define DBGL_INFO       (1 << 6)    // 提示消息,如驱动程序启动时,打印硬件消息
#define DBGL_DEBUG      (1 << 7)    // 调试消息,设置此级别会打印所有日志消息

#define DEFAULT_DBG_LEVEL (DBGL_EMERG | DBGL_ALERT  | DBGL_CRIT | DBGL_ERR | DBGL_WARNING |  DBGL_NOTICE)

#ifdef DBGLOG_WITHOUT_FILENAME_LINE
#define LOG_PRINT_MSG(mask,args...)     OpenChaoJi_debug_print_msg_info(NULL, 0, mask,##args)
#define LOG_PRINT_BUFF(mask,data,len)   OpenChaoJi_debug_print_buff(NULL, 0, mask, data, len)
#else
#define LOG_PRINT_MSG(mask,args...)     OpenChaoJi_debug_print_msg_info(__FILE__,__LINE__,mask,##args)
#define LOG_PRINT_BUFF(mask,data,len)   OpenChaoJi_debug_print_buff(__FILE__,__LINE__, mask, data, len)
#endif

// 如果SECC/EVCC的lib未定义Debug级别, 则使用该默认级别. Share库函数因为未使用SECC/EVCC lib的级别定义, 默认则使用该宏
// 建议使用DBGL_DEBUG 保证所有调试信息可能被打印. 如编译Binary大小敏感, 则可使用DBGL_INFO级别, 并在编译时定义DBGLOG_WITHOUT_FILENAME_LINE宏
// 一般不建议低于INFO级别, 否则大量日志可能无法获得, 尤其是中间报文信息
#ifndef OPENCHAOJI_DEFAULT_LOGLEVEL
#define OPENCHAOJI_DEFAULT_LOGLEVEL     DBGL_DEBUG
#endif

#if (OPENCHAOJI_DEFAULT_LOGLEVEL >= DBGL_DEBUG)
#define LOG_DEBUG(args...)              LOG_PRINT_MSG(DBGL_DEBUG, ##args)
#define LOG_BUFF_DEBUG(DATA, LEN)       LOG_PRINT_BUFF(DBGL_DEBUG, DATA, LEN)
#else
#define LOG_DEBUG(args...)
#define LOG_BUFF_DEBUG(DATA, LEN)
#endif

#if (OPENCHAOJI_DEFAULT_LOGLEVEL >= DBGL_INFO)
#define LOG_INFO(args...)               LOG_PRINT_MSG(DBGL_INFO, ##args)
#define LOG_BUFF_INFO(DATA, LEN)        LOG_PRINT_BUFF(DBGL_INFO, DATA, LEN)
#else
#define LOG_INFO(args...)
#define LOG_BUFF_INFO(DATA, LEN)
#endif

#if (OPENCHAOJI_DEFAULT_LOGLEVEL >= DBGL_NOTICE)
#define LOG_NOTICE(args...)             LOG_PRINT_MSG(DBGL_NOTICE, ##args)
#define LOG_BUFF_NOTICE(DATA, LEN)      LOG_PRINT_BUFF(DBGL_NOTICE, DATA, LEN)
#else
#define LOG_NOTICE(args...)
#define LOG_BUFF_NOTICE(DATA, LEN)
#endif

#if (OPENCHAOJI_DEFAULT_LOGLEVEL >= DBGL_WARNING)
#define LOG_WARNING(args...)            LOG_PRINT_MSG(DBGL_WARNING, ##args)
#define LOG_BUFF_WARNING(DATA, LEN)     LOG_PRINT_BUFF(DBGL_WARNING, DATA, LEN)
#else
#define LOG_WARNING(args...)
#define LOG_BUFF_WARNING(DATA, LEN)
#endif

#if (OPENCHAOJI_DEFAULT_LOGLEVEL >= DBGL_ERR)
#define LOG_ERR(args...)                LOG_PRINT_MSG(DBGL_ERR, ##args)
#define LOG_BUFF_ERR(DATA, LEN)         LOG_PRINT_BUFF(DBGL_ERR, DATA, LEN)
#else
#define LOG_ERR(args...)
#define LOG_BUFF_ERR(DATA, LEN)
#endif

#if (OPENCHAOJI_DEFAULT_LOGLEVEL >= DBGL_CRIT)
#define LOG_CRIT(args...)               LOG_PRINT_MSG(DBGL_CRIT, ##args)
#define LOG_BUFF_CRIT(DATA, LEN)        LOG_PRINT_BUFF(DBGL_CRIT, DATA, LEN)
#else
#define LOG_CRIT(args...)
#define LOG_BUFF_CRIT(DATA, LEN)
#endif

#if (OPENCHAOJI_DEFAULT_LOGLEVEL >= DBGL_ALERT)
#define LOG_ALERT(args...)              LOG_PRINT_MSG(DBGL_ALERT, ##args)
#define LOG_BUFF_ALERT(DATA, LEN)       LOG_PRINT_BUFF(DBGL_ALERT, DATA, LEN)
#else
#define LOG_ALERT(args...)
#define LOG_BUFF_ALERT(DATA, LEN)
#endif

#if (OPENCHAOJI_DEFAULT_LOGLEVEL >= DBGL_EMERG)
#define LOG_EMERG(args...)              LOG_PRINT_MSG(DBGL_EMERG, ##args)
#define LOG_BUFF_EMERG(DATA, LEN)       LOG_PRINT_BUFF(DBGL_EMERG, DATA, LEN)
#else
#define LOG_EMERG(args...)
#define LOG_BUFF_EMERG(DATA, LEN)
#endif


// 日志打印颜色宏定义
// 建议HAL在OpenChaoJi_debug_print_msg_info内使用以下宏实现颜色打印
// 紧急消息，红色加粗
#define COLOR_EMERG     "\033[1;31m"
// 报告消息，红色
#define COLOR_ALERT     "\033[31m"
// 临界消息，橙色
#define COLOR_CRIT      "\033[33m"
// 错误消息，紫色
#define COLOR_ERR       "\033[35m"
// 警告消息，黄色
#define COLOR_WARNING   "\033[36m"
// 通知消息，绿色
#define COLOR_NOTICE    "\033[32m"
// 提示消息，灰色
#define COLOR_INFO      "\033[37m"
// 调试消息，浅灰色
#define COLOR_DEBUG     "\033[90m"
// 恢复终端默认颜色
#define COLOR_RESET     "\033[0m"
// 下划线
#define ULINE_SET       "\033[4m"
// 闪烁
#define FLICK_SET       "\033[5m"
// 反转（反转前景色和背景色）
#define USHOW_SET       "\033[7m"

/**
 * Best Practice:
 * DEBUG:  打印循环信息, 例如所有的Loop循环 一般不使用, 仅用于实时判断循环是否正常运行
 * INFO:   打印数据触发信息, 例如CAN报文收发信息(传输层), 数据进出队列信息(DataBuff等), 底层CAN报文收发(HAL层)
 * NOTICE: 打印普通状态触发信息, 例如数据变化消息(system收发报文), 定时器timeout等
 * WARNING:打印重要状态触发信息, 例如System和Status切换(system变化) 导引状态变化(HAL层) 状态变化System消息(system状态变化)
 * ERROR:  打印普通错误信息, 例如CAN报文解析错误, 数据队列错误, 流程错误等
 * CRIT:   打印严重错误信息, 例如硬件错误(绝缘检测, PE短线, CP断开)等 内存错误等
 * ALERT:  打印紧急错误信息, 例如系统逻辑错误
 * EMERG:  打印系统崩溃信息, 例如紧急停机, Crash等
 */
/**
 * System 里面各种日志的级别
 */
#define LOG_STATUS_LOOP     LOG_DEBUG       // LOOP函数中不离开当前状态的打印, 即每次循环都会打印的情况
#define LOG_MSG_TIMEOUT     LOG_NOTICE      // LOOP函数中定时器超时发送下一个报文的情况
#define LOG_STATUS_CHANGE   LOG_WARNING     // LOOP函数中需要切换到另外一个状态前的情况, 定时器超时切换状态
#define LOG_STATUS_PREV     LOG_WARNING     // PREV函数
#define LOG_STATUS_POST     LOG_WARNING     // POST函数

/**
 * System/DataBuff/Transport 收发数据的日志级别
 */
#define LOG_DATA_NORMAL         LOG_INFO        // System/DataBuff收发的报文完整打印级别
#define LOG_DATA_BUFF_NORMAL    LOG_BUFF_INFO

#define LOG_DATA_CHANGE         LOG_NOTICE      // System/DataBuff收发的报文变化打印级别
#define LOG_DATA_BUFF_CHANGE    LOG_BUFF_NOTICE

#define LOG_DATA_LINKAGE        LOG_NOTICE      // 链路层所有报文需要打印, 不分是否变化
#define LOG_DATA_BUFF_LINKAGE   LOG_BUFF_NOTICE

#define LOG_PILOT               LOG_ALERT       // 导引变化需要立即打印

#define LOG_DATA_TRANSPORT      LOG_INFO        // 传输层的CAN收发报文打印, 还可以通过额外的开关进行控制
                                                // 一般跟HAL二选一打印即可, 除非初始验证CAN接口是否正常
#define LOG_DATA_BUFF_TRANSPORT LOG_BUFF_INFO

#define LOG_DATA_DATABUFF       LOG_INFO        // 数据缓冲的收发报文打印, 还可以通过额外的开关进行控制
                                                // 一般跟 LOG_DATA_NORMAL 二选一打印即可, 基本认为是等同的
#define LOG_DATA_BUFF_DATABUFF  LOG_BUFF_INFO

/**
 * Transport/HAL 收发数据的日志级别
 */
#define LOG_DATA_HAL            LOG_DEBUG
#define LOG_DATA_BUFF_HAL       LOG_BUFF_DEBUG

#define LOG_PILOT_HAL           LOG_ALERT

/**
 * 部分模块由于打印特别多, 可以设置单独开关, 与打印级别组合使用
 * 这些模块开关一般默认都是关的, 用于精简日志
 */
#define DBGM_TRANSPORT          (1 << 0)        // 传输层
#define DBGM_DATABUFF           (1 << 1)        // 数据缓冲
#define DBGM_GBT_B_PUBLIC       (1 << 2)        // B类系统的公共周期性报文(继电器,枪锁等报文)

void OpenChaoJi_debug_set_log_module_transport(bool enable);
void OpenChaoJi_debug_set_log_module_data_buff(bool enable);
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
void OpenChaoJi_debug_set_log_module_gbt_b_public(bool enable);
#endif
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
void OpenChaoJi_debug_set_log_module_gbt_a_public(bool enable);
#endif

/**
 * @brief  设置LOG打印水平
 * @param  level: 打印级别-8个打印级别的或结果, 表示是否打开某个级别
 */
void OpenChaoJi_debug_set_log_level(int level);

/**
 * @brief  获取LOG打印水平
 * @return level: 打印级别-8个打印级别的或结果, 表示是否打开某个级别
 */
int OpenChaoJi_debug_get_log_level();

/**
 * @brief  LOG打印
 * @param  filename: 文件名  line: 行号 mask: 打印级别掩码-或模式
 * @return format...:格式化参数
 */
void OpenChaoJi_debug_print_msg_info(char* filename, int line, int mask, const char *format, ...);

/**
 * @brief  数据打印
 * @param  DATA: 打印数据起始地址
 * @param  LEN: 打印数据长度
 */
void OpenChaoJi_debug_print_buff(char* filename, int line, int mask, const uint8_t * data, int len);

#endif

